using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
using Xeml.Document;
using Xeml.Document.Contracts;
using Mpi.Common.Collections;
using Mpi.Common;
using System.Globalization;
using Mpi.Common.Controls;
using System.Threading;

namespace Xid.Controls
{
    public partial class HtmlReportCtrl : UserControl, IBusyReporter
    {

        public HtmlReportCtrl()
        {
            InitializeComponent();
            buttonSpecRefresh.Click += new EventHandler(buttonSpecRefresh_Click);
            ExtractReportFiles();

            GenerateReport();


            //_busy.Text = "Please wait while genrating report...";
            //this.kryptonPanel1.Controls.Add(_busy);
            //_busy.Busy = false;

        }

        private string _reportFolder;
        private void ExtractReportFiles()
        {
            _reportFolder = Path.Combine(Path.GetTempPath(), "XemlReport");
            if (Directory.Exists(_reportFolder))
                Directory.Delete(_reportFolder, true);
            Directory.CreateDirectory(_reportFolder);
XemlReportRes.index_r1_c1.Save(Path.Combine(_reportFolder, "index_r1_c1.gif"), ImageFormat.Gif);
            XemlReportRes.background_blue.Save(Path.Combine(_reportFolder, "background_blue.jpg"), ImageFormat.Jpeg);
            
            XemlReportRes.index_r2_c1.Save(Path.Combine(_reportFolder, "index_r2_c1.gif"), ImageFormat.Gif);
            XemlReportRes.index_r2_c3.Save(Path.Combine(_reportFolder, "index_r2_c3.gif"), ImageFormat.Gif);
            XemlReportRes.index_r4_c1.Save(Path.Combine(_reportFolder, "index_r4_c1.gif"), ImageFormat.Gif);
            XemlReportRes.index_r3_c2.Save(Path.Combine(_reportFolder, "index_r3_c2.gif"), ImageFormat.Gif);
            XemlReportRes.spacer.Save(Path.Combine(_reportFolder, "spacer.gif"), ImageFormat.Gif);
            XemlReportRes.tdbackground.Save(Path.Combine(_reportFolder, "tdbackground.jpg"), ImageFormat.Jpeg);

            File.WriteAllText(Path.Combine(_reportFolder, "report_template.htm"), XemlReportRes.report_template);
            File.WriteAllText(Path.Combine(_reportFolder, "styles_blue.css"), XemlReportRes.styles_blue);
        }

        private IDocument _xemlDoc;
        public void Setup(IDocument xemlDoc)
        {

            _xemlDoc = xemlDoc;
            // GenerateReport();
        }

        public void GenerateReport()
        {

            OnBackgroundWorkStarted("Generating report.");
            try
            {
                if (_xemlDoc != null)
                {
                    CultureInfo ci = new CultureInfo("en-US");

                    string template = File.ReadAllText(Path.Combine(_reportFolder, "report_template.htm"));


                    template = template.Replace("$xeml_experimenter_firstname$", _xemlDoc.ExperimentHeader.Experimenter.FirstName);
                    template = template.Replace("$xeml_experimenter_lastname$", _xemlDoc.ExperimentHeader.Experimenter.LastName);
                    template = template.Replace("$xeml_experimenter_email$", _xemlDoc.ExperimentHeader.Experimenter.Email);
                    template = template.Replace("$xeml_experiment_description$", _xemlDoc.ExperimentHeader.Description);
                    template = template.Replace("$xeml_experimenter_organisation$", _xemlDoc.ExperimentHeader.Experimenter.Organisation);

                    template = template.Replace("$xeml_experiment_name$", _xemlDoc.Name);
                    template = template.Replace("$xeml_experiment_date$", _xemlDoc.StartDate.ToString("F", ci));
                    template = template.Replace("$xeml_ontology_table$", GenerateOntologyTable());
                    template = template.Replace("$xeml_sample_count$", GenerateSampleCount());
                    template = template.Replace("$xeml_observationpoint_count$", GenerateObPointCount());

                    template = template.Replace("$xeml_allparameter_table$", GenerateParameterTable());
                    template = template.Replace("$xeml_variables_table$", GenerateVariableParameterTable());
                    template = template.Replace("$xeml_material_table$", GenerateMaterialTable());
                    template = template.Replace("$xeml_observationschedule_table$", GenerateObservationScheduleTable(ci));

                    File.WriteAllText(Path.Combine(_reportFolder, "report.htm"), template);
                    webBrowser1.Navigate(@"file://" + Path.Combine(_reportFolder, "report.htm"));
                }
            }
            finally
            {

                OnBackgroundWorkEnded();
            }
            //string x = Properties.Resources.XEMLReport;
            //x = GenerateReport(x);


        }

        private string GenerateObservationScheduleTable(CultureInfo ci)
        {
            SortedDictionary<DateTime, List<object>> temp = new SortedDictionary<DateTime, List<object>>();
            foreach (TreeNode<StoryBase> sbnode in _xemlDoc.StoryBoard)
            {
                foreach (ObservationPoint op in sbnode.Content.ObservationPoints)
                {
                    List<object> row;

                    DateTime dat = _xemlDoc.StartDate + op.TimePoint;


                    if (temp.ContainsKey(dat))
                    {
                        row = temp[dat];
                        row[2] = ((TimeSpan)row[2]) + op.Duration;
                        row[3] = ((int)row[3]) + op.Observations.Count;
                    }
                    else
                    {
                        row = new List<object>();
                        row.Add(dat.ToString("D", ci));
                        row.Add(dat.ToString("T", ci));

                        row.Add(op.Duration);
                        row.Add(op.Observations.Count);
                        temp.Add(dat, row);
                    }
                }
            }

            StringBuilder sb = new StringBuilder();
            sb.Append("<table width=\"100%\"  bordercolor=\"#3399FF\" id=\"contenttable\">\r\n");
            sb.Append("<tr>\r\n");
            sb.Append("<th>Date</th>\r\n");
            sb.Append("<th>Time</th>\r\n");
            sb.Append("<th>Duration</th>\r\n");
            sb.Append("<th>#Individuals</th>\r\n");
            sb.Append("</tr>\r\n");

            foreach (List<object> row in temp.Values)
            {
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", row[0]);
                sb.AppendFormat("<td>{0}</td>\r\n", row[1]);
                sb.AppendFormat("<td>{0}</td>\r\n", row[2].ToString());
                sb.AppendFormat("<td>{0}</td>\r\n", row[3].ToString());
                sb.Append("</tr>");
            }

            sb.Append("</table>\r\n");

            return sb.ToString();

        }

        private string GenerateMaterialTable()
        {
            SortedDictionary<string, Term> matLsit = new SortedDictionary<string, Term>();
            foreach (TreeNode<StoryBase> sbnode in _xemlDoc.StoryBoard)
            {
                foreach (ObservationPoint op in sbnode.Content.ObservationPoints)
                {
                    foreach (Observation ob in op.Observations)
                    {
                        foreach (Partition part in ob.Partitions)
                        {
                            foreach (Term m in part.Material)
                            {
                                if (!matLsit.ContainsKey(m.TermId))
                                    matLsit.Add(m.TermId, m);
                            }
                        }
                    }
                }
            }

            StringBuilder sb = new StringBuilder();
            sb.Append("<table width=\"100%\"  bordercolor=\"#3399FF\" id=\"contenttable\">\r\n");
            sb.Append("<tr>\r\n");
            sb.Append("<th>NameSpaceAlias</th>\r\n");
            sb.Append("<th>Material</th>\r\n");
            sb.Append("<th>TermId</th>\r\n");
            sb.Append("</tr>\r\n");


            foreach (KeyValuePair<string, Term> kvp in matLsit)
            {
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", kvp.Value.NameSpaceAlias);
                sb.AppendFormat("<td>{0}</td>\r\n", kvp.Value.Name);
                sb.AppendFormat("<td>{0}</td>\r\n", kvp.Value.TermId);
                sb.Append("</tr>");
            }

            sb.Append("</table>\r\n");

            return sb.ToString();
        }

        private string GenerateSampleCount()
        {
            int count = 0;
            foreach (TreeNode<StoryBase> sb in _xemlDoc.StoryBoard)
            {
                foreach (Sample s in sb.Content.Samples)
                {
                    count++;
                }
            }
            return count.ToString();
        }

        private string GenerateObPointCount()
        {
            int count = 0;
            foreach (TreeNode<StoryBase> sb in _xemlDoc.StoryBoard)
            {
                foreach (ObservationPoint op in sb.Content.ObservationPoints)
                {
                    count++;
                }
            }
            return count.ToString();
        }

        private string GenerateParameterTable()
        {
            StringBuilder sb = new StringBuilder();
            int count = 0;
            SortedDictionary<string, Term> distinctParams = new SortedDictionary<string, Term>();
            foreach (TreeNode<StoryBase> sbnode in _xemlDoc.StoryBoard)
            {
                foreach (DynamicTerm p in sbnode.Content.Variables)
                {
                    if (!distinctParams.ContainsKey(p.TermId))
                    {
                        distinctParams.Add(p.TermId, p);
                    }
                }
            }


            sb.Append("<table width=\"100%\"  bordercolor=\"#3399FF\" id=\"contenttable\">\r\n");
            sb.Append("<tr>\r\n");
            sb.Append("<th>NameSpaceAlias</th>\r\n");
            sb.Append("<th>Variable</th>\r\n");
            sb.Append("<th>TermId</th>\r\n");
            sb.Append("</tr>\r\n");

            foreach (Term p in distinctParams.Values)
            {
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", p.NameSpaceAlias);
                sb.AppendFormat("<td>{0}</td>\r\n", p.Name);
                sb.AppendFormat("<td>{0}</td>\r\n", p.TermId);
                sb.Append("</tr>");

            }

            sb.Append("</table>\r\n");

            return sb.ToString();
        }

        private string GenerateVariableParameterTable()
        {
            StringBuilder sb = new StringBuilder();

            SortedDictionary<string, DynamicTerm> distinctParams = new SortedDictionary<string, DynamicTerm>();


            SortedDictionary<string, List<TimeSpan>> varTimes = new SortedDictionary<string, List<TimeSpan>>();
            foreach (TreeNode<StoryBase> sbnode in _xemlDoc.StoryBoard)
            {
                List<TimeSpan> timepoints;
                var vars = sbnode.Content.AllOverParameters();
                foreach (DynamicTerm p in vars.Keys)
                {

                    if (varTimes.ContainsKey(p.TermId))
                        timepoints = varTimes[p.TermId];
                    else
                        timepoints = new List<TimeSpan>();

                    foreach (var context in vars[p])
                    {
                        foreach (var t in sbnode.Content.HistoryValues(p.Name, context).Keys)
                        {
                            if (!timepoints.Contains(t))
                                timepoints.Add(t);

                        }
                    }

                    timepoints.Sort();
                    if (timepoints.Count > 0 && timepoints[timepoints.Count - 1] > TimeSpan.Zero)
                    {
                        if (!distinctParams.ContainsKey(p.TermId))
                            distinctParams.Add(p.TermId, p);
                        if (!varTimes.ContainsKey(p.TermId))
                            varTimes.Add(p.TermId, timepoints);
                    }

                }
            }


            sb.Append("<table width=\"100%\"  bordercolor=\"#3399FF\" id=\"contenttable\">\r\n");
            sb.Append("<tr>\r\n");
            sb.Append("<th>NameSpaceAlias</th>\r\n");
            sb.Append("<th>Variable</th>\r\n");
            sb.Append("<th>TermId</th>\r\n");
            sb.Append("<th>Changed at</th>\r\n");
            sb.Append("</tr>\r\n");

            foreach (DynamicTerm p in distinctParams.Values)
            {
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", p.NameSpaceAlias);
                sb.AppendFormat("<td>{0}</td>\r\n", p.Name);
                sb.AppendFormat("<td>{0}</td>\r\n", p.TermId);
                string times = "";
                foreach (TimeSpan ts in varTimes[p.TermId])
                {
                    if (ts > TimeSpan.Zero)
                    {
                        times += ts.ToString() + ",";
                    }
                }
                if (times.Length > 0)
                    times = times.Remove(times.Length - 1, 1);

                sb.AppendFormat("<td>{0}</td>\r\n", times);

                sb.Append("</tr>");

            }

            sb.Append("</table>\r\n");

            return sb.ToString();
        }


        private string GenerateOntologyTable()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<table width=\"100%\"  bordercolor=\"#3399FF\" id=\"contenttable\">\r\n");
            sb.Append("<tr>\r\n");
            sb.Append("<th>Alias</th>\r\n");
            sb.Append("<th>NameSpace</th>\r\n");
            sb.Append("<th>Ontology</th>\r\n");
            sb.Append("</tr>\r\n");

            foreach (OntologyHandlerResource ohr in _xemlDoc.DocumentResources.EnvironmentOntologyHandler)
            {
                ohr.LoadOntology();
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.NameSpaceAlias);
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.Handler.NameSpace);
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.Location);
                sb.Append("</tr>");


            }

            foreach (OntologyHandlerResource ohr in _xemlDoc.DocumentResources.OrganismStructureOntologyHandler)
            {
                ohr.LoadOntology(); //TODO: ontology should be loaded at init time of an object
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.NameSpaceAlias);
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.Handler.NameSpace);
                sb.AppendFormat("<td>{0}</td>\r\n", BreakUrl(ohr.Location));
                sb.Append("</tr>");
            }

            foreach (OntologyHandlerResource ohr in _xemlDoc.DocumentResources.GermPlasmOntologyHandler)
            {
                sb.Append("<tr>\r\n");
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.NameSpaceAlias);
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.Handler.NameSpace);
                sb.AppendFormat("<td>{0}</td>\r\n", ohr.Location);
                sb.Append("</tr>\r\n");
            }

            sb.Append("</table>\r\n");

            return sb.ToString();
        }

        private string BreakUrl(string url)
        {

            int breakPoint = url.IndexOf('/', Math.Min(50, url.Length - 1));
            if (breakPoint > 0)
                return url.Insert(breakPoint, "<br/>");
            else
                return url;
        }

        private void buttonSpecRefresh_Click(object sender, EventArgs e)
        {


            GenerateReport();

            //Thread.Sleep(1000);
            //_busy.Busy = false;
        }

        private void buttonSpecPrint_Click(object sender, EventArgs e)
        {
            webBrowser1.ShowPrintDialog();
        }

        private void buttonSpecPrintPreview_Click(object sender, EventArgs e)
        {
            webBrowser1.ShowPrintPreviewDialog();
        }

        private void buttonSpecSaveHtml_Click(object sender, EventArgs e)
        {
            webBrowser1.ShowSaveAsDialog();
        }


        public event EventHandler<BusyEventArgs> BackgroundWorkStarted;
        public event EventHandler BackgroundWorkEnded;

        protected virtual void OnBackgroundWorkStarted(string message)
        {
            if (BackgroundWorkStarted != null)
                BackgroundWorkStarted(this, new BusyEventArgs(message));
        }

        protected virtual void OnBackgroundWorkEnded()
        {
            if (BackgroundWorkEnded != null)
                BackgroundWorkEnded(this, new EventArgs());
        }


    }
}
